#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <bits/time.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <sched.h>

double get_current_time() {
  struct timespec ts;
  syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts);
  return (double)ts.tv_sec + (double)ts.tv_nsec * 1e-9; 
}

int main(int argc, char** argv) {
  char* trace_func = NULL;
  if (argc > 1) {
    trace_func = argv[1];
    printf("Tracing %s\n", trace_func);
  }
  int f = -1;
  char* fname = "/sys/kernel/debug/tracing/trace_pipe";
  double start_t = get_current_time();
  if ((f = open(fname, O_RDONLY|O_NONBLOCK)) < 0) {
    printf("Cannot open %s for reading: %s\n", fname, strerror(errno));
    return 0;
  }
  char pname[500], core[100], op[100] = "";
  double time, prev_time = 0, t = get_current_time();
  while (1) {
    char buf[1000] = "";
    int bytes_read = read(f, buf, 999);
    if (bytes_read == -1) {
      if (errno != 11) {
        printf("Cannot read %s: %s (%d)\n", fname, strerror(errno), errno);
        close(f);
        return 0;
      } else {
        //        printf("sleeping... \n");
        usleep(1000);//sched_yield();
      }
    } else if (bytes_read == 0) {
      printf("EOF for %s\n", fname);
      close(f);
      return 1;
    } else {
      buf[50] = '\0';
      // printf("%.4f Read %d bytes, first 50: %s\n", get_current_time() - start_t, bytes_read, buf);
      sscanf(buf, "%s %s %lf:", pname, core, &time);
      if (!trace_func || strstr(pname, trace_func)) {
        if (time - prev_time > 0.001) {
          if (prev_time > 0) {
            printf("%.4f: elapsed time %.6f\n", get_current_time() - t, time - prev_time);
            t = get_current_time();
          }
          prev_time = time;
        }
      }
    }
  }
  close(f);
  return 1;
}
